#pragma once
#include "common.h"
#include "cmath"
#define ENABLE_COUNTER 1
#if ENABLE_COUNTER

class Counter
{
private:
    uint64_t count = 0;
    static std::vector<Counter *> *counters;
    static int name_len_max;

public:
    std::string name;
    Counter(const std::string name) : name(name)
    {
        if (counters == NULL)
        {
            counters = new std::vector<Counter *>();
        }
        counters->push_back(this);
        if (name_len_max < name.length())
        {
            name_len_max = name.length();
        }
    }
    ~Counter()
    {
        if (counters == NULL)
            return;
        for (auto it = counters->begin(); it != counters->end(); it++)
        {
            if ((*it) == this)
            {
                counters->erase(it);
                break;
            }
        }
        if (counters->empty())
        {
            delete counters;
            counters = NULL;
        }
    }
    inline uint64_t operator++()
    {
        count++;
        return count;
    }
    inline uint64_t operator++(int)
    {
        return count++;
    }

    inline operator uint64_t() const
    {
        return count;
    }
    inline Counter &operator=(const uint64_t &other)
    {
        count = other;
        return *this;
    }

    friend std::ostream &operator<<(std::ostream &os, const Counter &obj)
    {
        os << COLOR("[Counter] ", GREEN) << std::setw(name_len_max) << std::setfill(' ') << std::left << obj.name << std::right << ":\t" << std::to_string(obj.count);
        return os;
    }
    static void print_counters()
    {
        std::cout << "====================[Counters]====================\n";
        std::sort(counters->begin(), counters->end(), [](const Counter *a, const Counter *b)
                  { return a->name < b->name; });
        for (auto counter : *counters)
        {
            std::cout << *counter << std::endl;
        }
        std::cout << "==================================================\n";
    }
};
#else
class Counter
{
private:
    uint64_t count = 0;
    static std::vector<Counter *> counters;

public:
    std::string name;
    Counter(const std::string name) : name(name)
    {
    }
    inline uint64_t operator++()
    {
        return 0;
    }
    inline uint64_t operator++(int)
    {
        return 0;
    }

    inline operator uint64_t() const
    {
        return 0;
    }
    inline Counter &operator=(const uint64_t &other)
    {
        return *this;
    }

    friend std::ostream &operator<<(std::ostream &os, const Counter &obj)
    {
        return os;
    }
    static void print_counters()
    {
        std::cout << "====================[Counters]====================\n";
        std::sort(counters->begin(), counters->end(), [](const Counter *a, const Counter *b)
                  { return a->name < b->name; });
        for (auto counter : counters)
        {
            std::cout << *counter << std::endl;
        }
        std::cout << "==================================================\n";
    }
};

#endif

uint64_t get_time_us();